package com.wwj.core.wawa.service.impl;

import com.egzosn.pay.common.api.PayConfigStorage;
import com.egzosn.pay.common.bean.*;
import com.egzosn.pay.wx.bean.WxTransactionType;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wwj.core.common.Constants;
import com.wwj.core.pay.bbn.BBNPaySDKConfig;
import com.wwj.core.pay.bbn.service.IBBNPayService;
import com.wwj.core.pay.weixin.handler.WaWaWxPayMessageHandler;
import com.wwj.core.system.entity.Parameter;
import com.wwj.core.system.entity.mapper.ParameterMapper;
import com.wwj.core.wawa.entity.*;
import com.wwj.core.wawa.entity.mapper.*;
import com.wwj.core.wawa.service.IPlayerRechargeService;
import com.wwj.pay.enums.PayType;
import com.wwj.pay.service.IApyAccountService;
import com.wwj.pay.service.PayResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by Administrator on 2017/11/3.
 */
@Service
public class PlayerRechargeServiceImpl implements IPlayerRechargeService {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Resource
    private PlayerRechargeMapper playerRechargeMapper;

    @Resource
    private ItemMapper itemMapper;

    @Resource
    private PlayerMapper playerMapper;

    @Resource
    private IBBNPayService bbnPayService;

    @Resource
    private PlayerItemMapper playerItemMapper;

    @Resource
    private PlayerItemChangeRecordMapper playerItemChangeRecordMapper;

    @Resource
    private ParameterMapper parameterMapper;

    @Resource
    private IApyAccountService apyAccountService;

    @Override
    public String dealPlayerRechargeByBBN(Integer playerId, Integer itemId, int payType, Integer couponId) {
        Player player = playerMapper.selectPlayerById(playerId);
        if(player == null) {
            throw new RuntimeException("购买失败，找不到玩家信息");
        }

        int money;
        String tradeNo = getTradeNo();
        PlayerRecharge playerRecharge = new PlayerRecharge();
        playerRecharge.setPlayerId(playerId);
        //支付运费
        if(itemId == -1) {
            Parameter freight = parameterMapper.selectParameterByCode(Constants.PARAM_FREIGHT);
            playerRecharge.setAmount(freight==null?new BigDecimal(15):new BigDecimal(Integer.valueOf(freight.getParamValue())));
            playerRecharge.setDescription("{\"nickname(\":\"" + player.getNickname() + "\"," + "\"description\":\"支付运费" + playerRecharge.getAmount() + "人民币\"}");
            money = playerRecharge.getAmount().multiply(new BigDecimal(100)).intValue();
        } else {
            Item item = itemMapper.selectItemById(itemId);
            if (item == null) {
                throw new RuntimeException("购买失败，找不到道具信息");
            }
            playerRecharge.setAmount(item.getMoney());
            playerRecharge.setDescription("{\"nickname(\":\"" + player.getNickname() + "\"," + "\"description\":\"购买" + item.getDescription() + ",花费" + item.getMoney() + "人民币\"}");
            money = item.getMoney().multiply(new BigDecimal(100)).intValue();
        }
        playerRecharge.setItemId(itemId);
        playerRecharge.setOrderTime(new Date());
        playerRecharge.setOrderStatus(PlayerRecharge.UNPAID);
        playerRecharge.setPayType(payType);
        playerRecharge.setPayPlatform(PlayerRecharge.PLATFORM_BBN);
        playerRecharge.setTradeNo(tradeNo);
        playerRechargeMapper.insertPlayerRecharge(playerRecharge);

        Parameter domain = parameterMapper.selectParameterByCode(Constants.PARAM_SYSTEM_DOMAIN);
        Parameter notify = parameterMapper.selectParameterByCode(Constants.PARAM_PAY_NOTIFY_URL);
        Parameter complete = parameterMapper.selectParameterByCode(Constants.PARAM_PAY_COMPLETE_URL);
        Parameter forward = parameterMapper.selectParameterByCode(Constants.PARAM_PAY_FORWARD_URL);
        String notifyUrl = domain.getParamValue() + notify.getParamValue();//支付平台支付完成后通知本系统的接口
        String payCompleteUrl = domain.getParamValue() + complete.getParamValue();//用户支付后浏览器端跳转网页地址
        String forwardUrl = domain.getParamValue() + forward.getParamValue();//支付页面地址，需要本系统内部转发

        // 支付参数
        Map<String, Object> paraMap = new HashMap<String, Object>();
        paraMap.put("goodsid", BBNPaySDKConfig.WARES_ID_0);
        paraMap.put("orderid", tradeNo);
        paraMap.put("playerid", playerId);
        paraMap.put("money", money);
        paraMap.put("notifyurl", notifyUrl);
        paraMap.put("backurl", payCompleteUrl);
        paraMap.put("paytype", payType);

        // 下单并生成支付URL
        Map<String, String> payRet = bbnPayService.placeOrder(paraMap);
        boolean success = Boolean.valueOf(payRet.get("success"));
        if (!success) {
            playerRecharge.setOrderStatus(PlayerRecharge.PAY_FAILD);
            playerRecharge.setTransState(Integer.valueOf(payRet.get("code")));
            playerRecharge.setTransResult(payRet.get("errmsg"));
            playerRechargeMapper.updatePlayerRecharge(playerRecharge);
            return null;
        } else {
            String payUrl = payRet.get("payUrl");
            String transId = payRet.get("transId");
            // 更新订单交易编号信息
            playerRecharge.setTransId(transId);
            playerRechargeMapper.updatePlayerRecharge(playerRecharge);

            payUrl = forwardUrl + "?url=" + payUrl;
            return payUrl;
        }
    }

    @Override
    public Map<String, Object> dealPlayerRechargeByApp(Integer playerId, Integer itemId, int payType, Integer couponId) {
        Player player = playerMapper.selectPlayerById(playerId);
        if(player == null) {
            throw new RuntimeException("购买失败，找不到玩家信息");
        }

        BigDecimal money;
        String title;
        String digest;
        String tradeNo = getTradeNo();
        PlayerRecharge playerRecharge = new PlayerRecharge();
        playerRecharge.setPlayerId(playerId);
        //支付运费
        if(itemId == -1) {
            Parameter freight = parameterMapper.selectParameterByCode(Constants.PARAM_FREIGHT);
            playerRecharge.setAmount(freight==null?new BigDecimal(15):new BigDecimal(Integer.valueOf(freight.getParamValue())));
            playerRecharge.setDescription("{\"nickname(\":\"" + player.getNickname() + "\"," + "\"description\":\"支付运费" + playerRecharge.getAmount() + "人民币\"}");
            money = playerRecharge.getAmount();
            title = "运费支付";
            digest = "申请一个娃娃发货需要支付运费";
        } else {
            Item item = itemMapper.selectItemById(itemId);
            if (item == null) {
                throw new RuntimeException("购买失败，找不到道具信息");
            }
            playerRecharge.setAmount(item.getMoney());
            playerRecharge.setDescription("{\"nickname(\":\"" + player.getNickname() + "\"," + "\"description\":\"购买" + item.getDescription() + ",花费" + item.getMoney() + "人民币\"}");
            money = item.getMoney();
            title = "购买支付";
            digest = "购买娃娃币";
        }
        playerRecharge.setItemId(itemId);
        playerRecharge.setOrderTime(new Date());
        playerRecharge.setOrderStatus(PlayerRecharge.UNPAID);
        playerRecharge.setPayType(payType);
        playerRecharge.setPayPlatform(PlayerRecharge.PLATFORM_APP);
        playerRecharge.setTradeNo(tradeNo);
        playerRechargeMapper.insertPlayerRecharge(playerRecharge);

        PayOrder order = new PayOrder(title, digest, money , tradeNo);
        //APP支付
        order.setTransactionType(WxTransactionType.APP);
        Map<String, Object> orderInfo;
        //获取支付订单信息
        if(payType == 1) {
            orderInfo = apyAccountService.getPayResponse(PayType.wxPay).getService().orderInfo(order);
        } else if(payType == 2) {
            orderInfo = apyAccountService.getPayResponse(PayType.aliPay).getService().orderInfo(order);
        } else {
            throw new RuntimeException("无法支付，错误的支付类型:" + payType);
        }
        orderInfo.put("tradeNo", tradeNo);
        return orderInfo;
    }

    @Override
    public synchronized boolean dealRechargeComplete(Integer playerId, String orderNo, boolean success, int transState) throws Exception {
        Player player = playerMapper.selectPlayerById(playerId);
        if(player == null) {
            logger.error("找不到玩家记录:[" + orderNo +"]");
            return false;
        }

        PlayerRecharge playerRecharge = playerRechargeMapper.selectPlayerRechargeByTradeNo(orderNo);
        if(playerRecharge == null) {
            logger.error("找不到玩家支付记录:[" + orderNo +"]");
            return false;
        }

        if(playerRecharge.getPlayerId() != playerId) {
            logger.error("玩家支付记录:[" + orderNo +"]支付人不一致");
            return false;
        }

        if(playerRecharge.getOrderStatus() == PlayerRecharge.PAY_SUCCESS) {
            logger.error("玩家支付记录:[" + orderNo +"]已支付,无需处理");
            return true;
        }

        if(success) {
            if(playerRecharge.getItemId() > 0) {
                Item item = itemMapper.selectItemById(playerRecharge.getItemId());
                if (item == null) {
                    logger.error("找不到道具记录:[" + orderNo + "]");
                    return false;
                }

                PlayerItem playerItem = playerItemMapper.selectPlayerItemByPlayerId(playerId);
                int oldNum = playerItem == null ? 0 : playerItem.getItemNum();
                int newNum = oldNum + item.getPayNum() + item.getGiveNum();
                String description = "购买道具，类型=" + item.getId()+ ",道具名称=" + item.getName() + ",数量=" + 1 + ",描述=购买("  + item.getPayNum() + ")赠送(" + item.getGiveNum() + ")";
                if(player.getHasFirstRecharge() == 0) {
                    description += "首冲赠送(" + item.getFirstRechargeGive() + ")";
                    newNum += item.getFirstRechargeGive();
                    player.setHasFirstRecharge(1);
                    playerMapper.updatePlayerHasFirstRecharge(playerId, player.getHasFirstRecharge());
                }
                PlayerItemChangeRecord playerItemChangeRecord = new PlayerItemChangeRecord();
                playerItemChangeRecord.setPlayerId(playerId);
                playerItemChangeRecord.setItemId(playerRecharge.getItemId());
                playerItemChangeRecord.setItemNum(1);
                playerItemChangeRecord.setChangeType(PlayerItemChangeRecord.TYPE_INCREASE);
                playerItemChangeRecord.setSubChangeType(PlayerItemChangeRecord.IN_SUB_TYPE_BUY);
                playerItemChangeRecord.setOldNum(oldNum);
                playerItemChangeRecord.setNewNum(newNum);
                playerItemChangeRecord.setDescription(description);
                playerItemChangeRecord.setChangeTime(new Date());
                playerItemChangeRecordMapper.insertPlayerItemChangeRecord(playerItemChangeRecord);

                if(playerItem == null) {
                    playerItem = new PlayerItem();
                    playerItem.setPlayerId(playerId);
                    List<Item> baseItem = itemMapper.selectItemsByType(1);
                    playerItem.setItemId(baseItem.get(0).getId());
                    playerItem.setItemNum(item.getPayNum() + item.getGiveNum());
                    playerItemMapper.insertPlayerItem(playerItem);
                } else {
                    playerItem.setItemNum(item.getPayNum() + item.getGiveNum());
                    playerItemMapper.updatePlayerItem(playerItem);
                }
                playerRecharge.setChangeId(playerItemChangeRecord.getId());
            }

            playerRecharge.setOrderStatus(PlayerRecharge.PAY_SUCCESS);
            playerRecharge.setTransState(transState);
            playerRecharge.setPayTime(new Date());
            playerRecharge.setTransResult("支付成功");
            playerRechargeMapper.updatePlayerRecharge(playerRecharge);
        } else {
            playerRecharge.setOrderStatus(PlayerRecharge.PAY_FAILD);
            playerRecharge.setTransState(transState);
            playerRecharge.setPayTime(new Date());
            playerRecharge.setTransResult("支付失败");
            playerRechargeMapper.updatePlayerRecharge(playerRecharge);
        }
        return true;
    }

    @Override
    public Page<PlayerRecharge> findByPage(int offset, int limit, Map<String, Object> params) {
        PageHelper.offsetPage(offset, limit);
        return (Page<PlayerRecharge>)playerRechargeMapper.selectPlayerRecharges(params);
    }

    @Override
    public PlayerRecharge findByTradeNo(String tradeNo) {
        return playerRechargeMapper.selectPlayerRechargeByTradeNo(tradeNo);
    }

    @Override
    public synchronized String dealWxRechargeComplete(HttpServletRequest request) throws IOException {
        PayResponse payResponse = apyAccountService.getPayResponse(PayType.wxPay);
        PayConfigStorage storage = payResponse.getStorage();
        //获取支付方返回的对应参数
        Map<String, Object> params = payResponse.getService().getParameter2Map(request.getParameterMap(), request.getInputStream());
        if (null == params) {
            return payResponse.getService().getPayOutMessage("fail", "失败").toMessage();
        }
        //校验
        if (payResponse.getService().verify(params)) {
            payResponse.buildRouter(new WaWaWxPayMessageHandler(apyAccountService.getPayId(PayType.wxPay)), null, PayType.wxPay, MsgType.xml);
            PayMessage message = new PayMessage(params, storage.getPayType(), storage.getMsgType().name());
            PayOutMessage outMessage = payResponse.getRouter().route(message);
            return outMessage.toMessage();
        }
        return payResponse.getService().getPayOutMessage("fail", "失败").toMessage();
    }

    @Override
    public void dealCancelPlayerRecharge(String tradeNo) {
        PlayerRecharge playerRecharge = playerRechargeMapper.selectPlayerRechargeByTradeNo(tradeNo);
        if(playerRecharge != null) {
            playerRecharge.setOrderStatus(PlayerRecharge.PAY_CANCEL);
            playerRecharge.setPayTime(new Date());
            playerRecharge.setTransResult("用户取消支付");
            playerRechargeMapper.updatePlayerRecharge(playerRecharge);
        }
    }

    private synchronized String getTradeNo() {
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        Date date = new Date();
        String key = format.format(date);
        key += randomNumberString(6);
        return key;
    }

    private synchronized String randomNumberString(int length) {
        if (length < 1) {
            return null;
        }
        Random randGen = new Random();
        char[] numbersAndLetters = ("0123456789").toCharArray();
        char[] randBuffer = new char[length];
        for (int i = 0; i < randBuffer.length; i++) {
            randBuffer[i] = numbersAndLetters[randGen.nextInt(10)];
        }
        return new String(randBuffer);
    }
}
